package com.hsl.hslcodemother.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.hsl.hslcodemother.ai.core.AiCodeGeneratorFacade;
import com.hsl.hslcodemother.ai.model.enums.CodeGenTypeEnum;
import com.hsl.hslcodemother.constant.AppConstant;
import com.hsl.hslcodemother.exception.BusinessException;
import com.hsl.hslcodemother.exception.ErrorCode;
import com.hsl.hslcodemother.exception.ThrowUtils;
import com.hsl.hslcodemother.model.dto.app.AppQueryRequest;
import com.hsl.hslcodemother.model.entity.User;
import com.hsl.hslcodemother.model.vo.AppVO;
import com.hsl.hslcodemother.model.vo.UserVO;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.hsl.hslcodemother.model.entity.App;
import com.hsl.hslcodemother.mapper.AppMapper;
import com.hsl.hslcodemother.service.AppService;
import com.hsl.hslcodemother.service.ChatHistoryService;
import com.hsl.hslcodemother.service.UserService;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Map;
import java.util.Set;

import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import reactor.core.publisher.Flux;

/**
 * 服务层实现。
 *
 * @author <a href="https://gitee.com/liul3">猴赛雷</a>
 */
@Service
public class AppServiceImpl extends ServiceImpl<AppMapper, App> implements AppService {
    @Resource
    private UserService userService;
    @Resource
    @Lazy
    private ChatHistoryService chatHistoryService;
    @Resource
    private AiCodeGeneratorFacade aiCodeGeneratorFacade;

    @Override
    public QueryWrapper getQueryWrapper(AppQueryRequest appQueryRequest) {
        if (appQueryRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数为空");
        }
        Long id = appQueryRequest.getId();
        String appName = appQueryRequest.getAppName();
        Long userId = appQueryRequest.getUserId();
        String cover = appQueryRequest.getCover();
        Integer priority = appQueryRequest.getPriority();
        String codeGenType = appQueryRequest.getCodeGenType();
        String sortField = appQueryRequest.getSortField();
        String sortOrder = appQueryRequest.getSortOrder();
        QueryWrapper query = QueryWrapper.create()
                .eq("id", id)
                .eq("userId", userId)
                .eq("priority", priority)
                .eq("cover", cover)
                .eq("codeGenType", codeGenType)
                .like("appName", appName);
        if (StrUtil.isNotBlank(sortField)) {
            query.orderBy(sortField, "ascend".equals(sortOrder));
        }
        return query;
    }

    @Override
    public AppVO getAppVO(App app) {
        if (app == null) {
            return null;
        }
        AppVO appVO = new AppVO();
        BeanUtil.copyProperties(app, appVO);
        return appVO;
    }

    @Override
    public List<AppVO> getAppVOList(List<App> appList) {
        if (CollUtil.isEmpty(appList)) {
            return new ArrayList<>();
        }
        return appList.stream().map(this::getAppVO).collect(Collectors.toList());
    }

    @Override
    public List<AppVO> fillUsers(List<AppVO> appVOList) {
        if (CollUtil.isEmpty(appVOList)) {
            return appVOList;
        }
        Set<Long> userIds = appVOList.stream()
                .map(AppVO::getUserId)
                .filter(id -> id != null && id > 0)
                .collect(Collectors.toSet());
        if (CollUtil.isEmpty(userIds)) {
            return appVOList;
        }
        List<User> users = userService.listByIds(userIds);
        Map<Long, UserVO> idToUserVO = users.stream()
                .collect(Collectors.toMap(User::getId, u -> userService.getUserVO(u)));
        for (AppVO vo : appVOList) {
            if (vo.getUserId() != null) {
                vo.setUser(idToUserVO.get(vo.getUserId()));
            }
        }
        return appVOList;
    }

    @Override
    public Flux<String> chatToGenCode(Long appId, String message, User loginUser) {
        // 1. 参数校验
        ThrowUtils.throwIf(appId == null || appId <= 0, ErrorCode.PARAMS_ERROR, "应用 ID 不能为空");
        ThrowUtils.throwIf(StrUtil.isBlank(message), ErrorCode.PARAMS_ERROR, "用户消息不能为空");
        // 2. 查询应用信息
        App app = this.getById(appId);
        ThrowUtils.throwIf(app == null, ErrorCode.NOT_FOUND_ERROR, "应用不存在");
        // 3. 验证用户是否有权限访问该应用，仅本人可以生成代码
        if (!app.getUserId().equals(loginUser.getId())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "无权限访问该应用");
        }
        // 4. 获取应用的代码生成类型
        String codeGenTypeStr = app.getCodeGenType();
        CodeGenTypeEnum codeGenTypeEnum = CodeGenTypeEnum.getEnumByValue(codeGenTypeStr);
        if (codeGenTypeEnum == null) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "不支持的代码生成类型");
        }
        // 5. 调用 AI 生成代码
        return aiCodeGeneratorFacade.generateAndSaveCodeStream(message, codeGenTypeEnum, appId);
    }

    @Override
    public String deployApp(Long appId, User loginUser) {
        // 1. 参数校验
        ThrowUtils.throwIf(appId == null || appId <= 0, ErrorCode.PARAMS_ERROR, "应用 ID 不能为空");
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR, "用户未登录");
        // 2. 查询应用信息
        App app = this.getById(appId);
        ThrowUtils.throwIf(app == null, ErrorCode.NOT_FOUND_ERROR, "应用不存在");
        // 3. 验证用户是否有权限部署该应用，仅本人可以部署
        if (!app.getUserId().equals(loginUser.getId())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "无权限部署该应用");
        }
        // 4. 检查是否已有 deployKey
        String deployKey = app.getDeployKey();
        // 没有则生成 6 位 deployKey（大小写字母 + 数字）
        if (StrUtil.isBlank(deployKey)) {
            deployKey = RandomUtil.randomString(6);
        }
        // 5. 获取代码生成类型，构建源目录路径
        String codeGenType = app.getCodeGenType();
        String sourceDirName = codeGenType + "_" + appId;
        String sourceDirPath = AppConstant.CODE_OUTPUT_ROOT_DIR + File.separator + sourceDirName;
        // 6. 检查源目录是否存在
        File sourceDir = new File(sourceDirPath);
        if (!sourceDir.exists() || !sourceDir.isDirectory()) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "应用代码不存在，请先生成代码");
        }
        // 7. 复制文件到部署目录
        String deployDirPath = AppConstant.CODE_DEPLOY_ROOT_DIR + File.separator + deployKey;
        try {
            FileUtil.copyContent(sourceDir, new File(deployDirPath), true);
        } catch (Exception e) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "部署失败：" + e.getMessage());
        }
        // 8. 更新应用的 deployKey 和部署时间
        App updateApp = new App();
        updateApp.setId(appId);
        updateApp.setDeployKey(deployKey);
        updateApp.setDeployedTime(LocalDateTime.now());
        boolean updateResult = this.updateById(updateApp);
        ThrowUtils.throwIf(!updateResult, ErrorCode.OPERATION_ERROR, "更新应用部署信息失败");
        // 9. 返回可访问的 URL
        return String.format("%s/%s/", AppConstant.CODE_DEPLOY_HOST, deployKey);
    }

    @Override
    public boolean removeById(Serializable id) {
        // 删除应用前，先删除关联的对话历史
        if (id != null) {
            chatHistoryService.deleteByAppId((Long) id);
        }
        return super.removeById(id);
    }
}
